/*
 *  script parser for finsh shell.
 *
 * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
 *
 *  This file is part of RT-Thread (http://www.rt-thread.org)
 *  Maintainer: bernard.xiong <bernard.xiong at gmail.com>
 *
 *  All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Change Logs:
 * Date           Author       Notes
 * 2010-03-22     Bernard      first version
 * 2013-10-09     Bernard      fix the command line too long issue.
 */
#include <finsh.h>

#include "finsh_token.h"
#include "finsh_node.h"
#include "finsh_error.h"
#include "finsh_parser.h"
#include "finsh_var.h"

/*
 * the structure of abstract syntax tree:
 * root____________
 * |               \
 * child__        sibling__
 * |      \       |        \
 * child sibling  child   sibling
 *                          ...
 */
static enum finsh_type proc_type(struct finsh_parser* self);
static int proc_identifier(struct finsh_parser* self, char* id);
static struct finsh_node* proc_variable_decl(struct finsh_parser* self);
static struct finsh_node* proc_expr(struct finsh_parser* self);
static struct finsh_node* proc_assign_expr(struct finsh_parser* self);
static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self);
static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self);
static struct finsh_node* proc_and_expr(struct finsh_parser* self);
static struct finsh_node* proc_shift_expr(struct finsh_parser* self);
static struct finsh_node* proc_additive_expr(struct finsh_parser* self);
static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self);
static struct finsh_node* proc_cast_expr(struct finsh_parser* self);
static struct finsh_node* proc_unary_expr(struct finsh_parser* self);
static struct finsh_node* proc_postfix_expr(struct finsh_parser* self);
static struct finsh_node* proc_primary_expr(struct finsh_parser* self);
static struct finsh_node* proc_param_list(struct finsh_parser* self);
static struct finsh_node* proc_expr_statement(struct finsh_parser* self);
static struct finsh_node* make_sys_node(uint8_t type, struct finsh_node* node1,
                                        struct finsh_node* node2);

/* check token */
#define check_token(token, lex, type) if ( (token) != (type) ) \
    { \
        finsh_error_set(FINSH_ERROR_INVALID_TOKEN); \
        finsh_token_replay(lex); \
    }

/* is the token a data type? */
#define is_base_type(token) ((token) == finsh_token_type_void \
    || (token) == finsh_token_type_char \
    || (token) == finsh_token_type_short \
    || (token) == finsh_token_type_int \
    || (token) == finsh_token_type_long)

/* get the next token */
#define next_token(token, lex)  (token) = finsh_token_token(lex)

/* match a specified token */
#define match_token(token, lex, type)   next_token(token, lex); \
    check_token(token, lex, type)

/*
process for function and variable declaration.
decl_variable -> type declaration_list ';'
declarator_list -> declarator_list ',' declarator
    | declarator
declarator -> identifier
    | identifier ASSIGN expr_assign
*/
static struct finsh_node* proc_variable_decl(struct finsh_parser* self)
{
	enum finsh_token_type token;
	enum finsh_type type;
	char id[FINSH_NAME_MAX + 1];

	struct finsh_node* node;
	struct finsh_node* end;
	struct finsh_node* assign;

	node = NULL;
	end  = NULL;

	/* get type */
	type = proc_type(self);

	/*process id.*/
	if(proc_identifier(self, id) == 0) {
		/* if add variable failed */
		if(finsh_var_insert(id, type) < 0) {
			finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
		}
	}

	next_token(token, &(self->token));

	switch(token) {
		case finsh_token_type_comma:/*',', it's a variable_list declaration.*/
			if(proc_identifier(self, id) == 0) {
				/* if add variable failed */
				if(finsh_var_insert(id, type) < 0) {
					finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
				}
			}

			next_token(token, &(self->token));

			if(token == finsh_token_type_assign) {
				/* get the right side of assign expression */
				assign = proc_assign_expr(self);

				if(assign != NULL) {
					struct finsh_node* idnode;

					idnode = finsh_node_new_id(id);
					end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
					node = end;

					next_token(token, &(self->token));
				}
			}

			while(token == finsh_token_type_comma) {
				if(proc_identifier(self, id) == 0) {
					/* if add variable failed */
					if(finsh_var_insert(id, type) < 0) {
						finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
					}
				}

				next_token(token, &(self->token));

				if(token == finsh_token_type_assign) {
					/* get the right side of assign expression */
					assign = proc_assign_expr(self);

					if(assign != NULL) {
						struct finsh_node* idnode;

						idnode = finsh_node_new_id(id);

						/* make assign expression node */
						if(node != NULL) {
							finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
							end = finsh_node_sibling(end);
						} else {
							end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
							node = end;
						}

						next_token(token, &(self->token));
					}
				}
			}

			check_token(token, &(self->token), finsh_token_type_semicolon);
			return node;

		case finsh_token_type_assign: { /*'=', it's a variable with assign declaration.*/
			struct finsh_node* idnode;

			assign = proc_assign_expr(self);

			if(assign != NULL) {
				idnode = finsh_node_new_id(id);

				/* make assign expression node */
				end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
				node = end;

				next_token(token, &(self->token));
			}

			while(token == finsh_token_type_comma) {
				if(proc_identifier(self, id) == 0) {
					/* if add variable failed */
					if(finsh_var_insert(id, type) < 0) {
						finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
					}
				}

				next_token(token, &(self->token));

				if(token == finsh_token_type_assign) {
					/* get the right side of assign expression */
					assign = proc_assign_expr(self);

					if(assign != NULL) {
						idnode = finsh_node_new_id(id);

						/* make assign expression node */
						if(node != NULL) {
							finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
							end = finsh_node_sibling(end);
						} else {
							end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
							node = end;
						}

						next_token(token, &(self->token));
					}
				}
			}

			check_token(token, &(self->token), finsh_token_type_semicolon);
			return node;
		}

		case finsh_token_type_semicolon:/*';', it's a variable declaration.*/
			return node;

		default:
			finsh_error_set(FINSH_ERROR_EXPECT_TYPE);

			return NULL;
	}
}

/*
type -> type_prefix type_basic | type_basic
type_prefix -> UNSIGNED
type_basic -> VOID
    | CHAR
    | SHORT
    | INT
    | STRING
*/
static enum finsh_type proc_type(struct finsh_parser* self)
{
	enum finsh_type type;
	enum finsh_token_type token;

	/* set init type */
	type = finsh_type_unknown;

	next_token(token, &(self->token));

	if(is_base_type(token)) {  /* base_type */
		switch(token) {
			case finsh_token_type_void:
				type = finsh_type_void;
				break;

			case finsh_token_type_char:
				type = finsh_type_char;
				break;

			case finsh_token_type_short:
				type = finsh_type_short;
				break;

			case finsh_token_type_int:
				type = finsh_type_int;
				break;

			case finsh_token_type_long:
				type = finsh_type_long;
				break;

			default:
				goto __return;
		}
	} else if(token == finsh_token_type_unsigned) { /* unsigned base_type */
		next_token(token, &(self->token));

		if(is_base_type(token)) {
			switch(token) {
				case finsh_token_type_char:
					type = finsh_type_uchar;
					break;

				case finsh_token_type_short:
					type = finsh_type_ushort;
					break;

				case finsh_token_type_int:
					type = finsh_type_uint;
					break;

				case finsh_token_type_long:
					type = finsh_type_ulong;
					break;

				default:
					goto __return;
			}
		} else {
			finsh_token_replay(&(self->token));
			finsh_error_set(FINSH_ERROR_EXPECT_TYPE);
		}
	} else {
		goto __return;
	}

	/* parse for pointer */
	next_token(token, &(self->token));

	if(token == finsh_token_type_mul) {
		switch(type) {
			case finsh_type_void:
				type = finsh_type_voidp;
				break;

			case finsh_type_char:
			case finsh_type_uchar:
				type = finsh_type_charp;
				break;

			case finsh_type_short:
			case finsh_type_ushort:
				type = finsh_type_shortp;
				break;

			case finsh_type_int:
			case finsh_type_uint:
				type = finsh_type_intp;
				break;

			case finsh_type_long:
			case finsh_type_ulong:
				type = finsh_type_longp;
				break;

			default:
				type = finsh_type_voidp;
				break;
		}
	} else finsh_token_replay(&(self->token));

	return type;

__return:
	finsh_token_replay(&(self->token));
	finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE);

	return type;
}

/*
identifier -> IDENTIFIER
*/
static int proc_identifier(struct finsh_parser* self, char* id)
{
	enum finsh_token_type token;

	match_token(token, &(self->token), finsh_token_type_identifier);

	strncpy(id, (char*)self->token.string, FINSH_NAME_MAX);

	return 0;
}

/*
statement_expr -> ';'
    | expr ';'
*/
static struct finsh_node* proc_expr_statement(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* expr;

	expr = NULL;
	next_token(token, &(self->token));

	if(token != finsh_token_type_semicolon) {
		finsh_token_replay(&(self->token));
		expr = proc_expr(self);

		match_token(token, &(self->token), finsh_token_type_semicolon);
	}

	return expr;
}

/*
expr -> expr_assign
*/
static struct finsh_node* proc_expr(struct finsh_parser* self)
{
	return proc_assign_expr(self);
}

/*
expr_assign -> expr_inclusive_or
    | expr_unary ASSIGN expr_assign
*/
static struct finsh_node* proc_assign_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* or;
	struct finsh_node* assign;

	or = proc_inclusive_or_expr(self);

	next_token(token, &(self->token));

	if(token == finsh_token_type_assign) {
		assign = proc_assign_expr(self);

		return make_sys_node(FINSH_NODE_SYS_ASSIGN, or, assign);
	} else finsh_token_replay(&(self->token));

	return or;
}

/*
expr_inclusive_or -> expr_exclusive_or
    | expr_inclusive_or '|' expr_exclusive_or
*/
static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* xor;
	struct finsh_node* xor_new;

	xor = proc_exclusive_or_expr(self);

	next_token(token, &(self->token));

	while(token == finsh_token_type_or) {
		xor_new = proc_exclusive_or_expr(self);

		if(xor_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
		else xor = make_sys_node(FINSH_NODE_SYS_OR, xor, xor_new);

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return xor;
}

/*
expr_exclusive_or -> expr_and
    | expr_exclusive '^' expr_and
*/
static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* and;
	struct finsh_node* and_new;

	and = proc_and_expr(self);
	next_token(token, &(self->token));

	while(token == finsh_token_type_xor) {
		and_new = proc_and_expr(self);

		if(and_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
		else and = make_sys_node(FINSH_NODE_SYS_XOR, and, and_new);

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return and;
}

/*
expr_and -> expr_shift
    | expr_and '&' expr_shift
*/
static struct finsh_node* proc_and_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* shift;
	struct finsh_node* shift_new;

	shift = proc_shift_expr(self);

	next_token(token, &(self->token));

	while(token == finsh_token_type_and) {
		shift_new = proc_shift_expr(self);

		if(shift_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
		else shift = make_sys_node(FINSH_NODE_SYS_AND, shift, shift_new);

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return shift;
}

/*
expr_shift -> expr_additive
    | expr_shift '<<' expr_additive
    | expr_shift '>>' expr_additive
*/
static struct finsh_node* proc_shift_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* add;
	struct finsh_node* add_new;

	add = proc_additive_expr(self);

	next_token(token, &(self->token));

	while(token == finsh_token_type_shl || token == finsh_token_type_shr) {
		add_new = proc_additive_expr(self);

		if(add_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
		else {
			switch(token) {
				case finsh_token_type_shl:
					add = make_sys_node(FINSH_NODE_SYS_SHL, add, add_new);
					break;

				case finsh_token_type_shr:
					add = make_sys_node(FINSH_NODE_SYS_SHR, add, add_new);
					break;

				default:
					finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
					break;
			}
		}

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return add;
}

/*
expr_additive -> expr_multiplicative
    | expr_additive SUB expr_multiplicative
    | expr_additive ADD expr_multiplicative
*/
static struct finsh_node* proc_additive_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* mul;
	struct finsh_node* mul_new;

	mul = proc_multiplicative_expr(self);

	next_token(token, &(self->token));

	while(token == finsh_token_type_sub || token == finsh_token_type_add) {
		mul_new = proc_multiplicative_expr(self);

		if(mul_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
		else {
			switch(token) {
				case finsh_token_type_sub:
					mul = make_sys_node(FINSH_NODE_SYS_SUB, mul, mul_new);
					break;

				case finsh_token_type_add:
					mul = make_sys_node(FINSH_NODE_SYS_ADD, mul, mul_new);
					break;

				default:
					finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
					break;
			}
		}

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return mul;
}

/*
expr_multiplicative -> expr_cast
    | expr_multiplicative '*' expr_cast
    | expr_multiplicative '/' expr_cast
    | expr_multiplicative '%' expr_cast
*/
static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* cast;
	struct finsh_node* cast_new;

	cast = proc_cast_expr(self);
	next_token(token, &(self->token));

	while(token == finsh_token_type_mul ||
	        token == finsh_token_type_div ||
	        token == finsh_token_type_mod) {
		cast_new = proc_cast_expr(self);

		if(cast_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
		else {
			switch(token) {
				case finsh_token_type_mul:
					cast = make_sys_node(FINSH_NODE_SYS_MUL, cast, cast_new);
					break;

				case finsh_token_type_div:
					cast = make_sys_node(FINSH_NODE_SYS_DIV, cast, cast_new);
					break;

				case finsh_token_type_mod:
					cast = make_sys_node(FINSH_NODE_SYS_MOD, cast, cast_new);
					break;

				default:
					finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
					break;
			}
		}

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return cast;
}

/*
20060313, add recast parse
expr_cast -> expr_unary
    | '(' type ')' expr_cast
*/
static struct finsh_node* proc_cast_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	enum finsh_type type;
	struct finsh_node* cast;

	next_token(token, &(self->token));

	if(token == finsh_token_type_left_paren) {
		type = proc_type(self);
		match_token(token, &(self->token), finsh_token_type_right_paren);

		cast = proc_cast_expr(self);

		if(cast != NULL) {
			cast->data_type = type;
			return cast;
		}
	}

	finsh_token_replay(&(self->token));
	return proc_unary_expr(self);
}

/*
20050921, add '*' and '&'
expr_unary -> expr_postfix
    | ADD expr_cast
    | INC expr_cast
    | SUB expr_cast
    | DEC expr_cast
    | '~' expr_cast
    | '*' expr_cast
    | '&' expr_cast
*/
static struct finsh_node* proc_unary_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* cast;

	next_token(token, &(self->token));

	switch(token) {
		case finsh_token_type_add: /* + */
			cast = proc_cast_expr(self);
			return cast;

		case finsh_token_type_inc: /* ++ */
			cast = proc_cast_expr(self);
			return make_sys_node(FINSH_NODE_SYS_PREINC, cast, NULL);

		case finsh_token_type_sub: /* - */
			cast = proc_cast_expr(self);
			return make_sys_node(FINSH_NODE_SYS_SUB, finsh_node_new_long(0), cast);

		case finsh_token_type_dec: /* -- */
			cast = proc_cast_expr(self);
			return make_sys_node(FINSH_NODE_SYS_PREDEC, cast, NULL);

		case finsh_token_type_bitwise: /* ~ */
			cast = proc_cast_expr(self);
			return make_sys_node(FINSH_NODE_SYS_BITWISE, cast, NULL);

		case finsh_token_type_mul: /* * */
			cast = proc_cast_expr(self);
			return make_sys_node(FINSH_NODE_SYS_GETVALUE, cast, NULL);

		case finsh_token_type_and: /* & */
			cast = proc_cast_expr(self);
			return make_sys_node(FINSH_NODE_SYS_GETADDR, cast, NULL);

		default:
			finsh_token_replay(&(self->token));
			return proc_postfix_expr(self);
	}
}

/*
expr_postfix -> expr_primary
    | expr_postfix INC
    | expr_postfix DEC
    | expr_postfix '(' param_list ')'
*/
static struct finsh_node* proc_postfix_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* postfix;

	postfix = proc_primary_expr(self);

	next_token(token, &(self->token));

	while(token == finsh_token_type_inc   ||
	        token == finsh_token_type_dec       ||
	        token == finsh_token_type_left_paren) {
		switch(token) {
			case finsh_token_type_inc :/* '++' */
				postfix = make_sys_node(FINSH_NODE_SYS_INC, postfix, NULL);
				break;

			case finsh_token_type_dec :/* '--' */
				postfix = make_sys_node(FINSH_NODE_SYS_DEC, postfix, NULL);
				break;

			case finsh_token_type_left_paren : { /* '(' */
				struct finsh_node* param_list;

				param_list = NULL;
				next_token(token, &(self->token));

				if(token != finsh_token_type_right_paren) {
					finsh_token_replay(&(self->token));
					param_list = proc_param_list(self);

					match_token(token, &(self->token), finsh_token_type_right_paren);
				}

				postfix = make_sys_node(FINSH_NODE_SYS_FUNC, postfix, param_list);
			}
			break;

			default:
				break;
		}

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));
	return postfix;
}

/*
expr_primary -> literal
    | '(' expr ')'
    | identifier
*/
static struct finsh_node* proc_primary_expr(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* expr;

	next_token(token, &(self->token));

	switch(token) {
		case finsh_token_type_identifier: {
			char id[FINSH_NAME_MAX + 1];

			finsh_token_replay(&(self->token));
			proc_identifier(self, id);
			return finsh_node_new_id(id);
		}

		case finsh_token_type_left_paren:
			expr = proc_expr(self);
			match_token(token, &(self->token), finsh_token_type_right_paren);
			return expr;

		case finsh_token_type_value_int:
			return finsh_node_new_int(self->token.value.int_value);

		case finsh_token_type_value_long:
			return finsh_node_new_long(self->token.value.long_value);

		case finsh_token_type_value_char:
			return finsh_node_new_char(self->token.value.char_value);

		case finsh_token_type_value_string:
			return finsh_node_new_string((char*)self->token.string);

		case finsh_token_type_value_null:
			return finsh_node_new_ptr(NULL);

		default:
			finsh_error_set(FINSH_ERROR_INVALID_TOKEN);
			break;
	}

	return NULL;
}

/*
param_list -> empty
    | expr_assign
    | param_list ',' expr_assign
*/
static struct finsh_node* proc_param_list(struct finsh_parser* self)
{
	enum finsh_token_type token;
	struct finsh_node* node, *assign;

	assign = proc_assign_expr(self);

	if(assign == NULL) return NULL;

	node = assign;

	next_token(token, &(self->token));

	while(token == finsh_token_type_comma) {
		finsh_node_sibling(assign) = proc_assign_expr(self);

		if(finsh_node_sibling(assign) != NULL) assign = finsh_node_sibling(assign);
		else finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);

		next_token(token, &(self->token));
	}

	finsh_token_replay(&(self->token));

	return node;
}

/*
make a new node as following tree:
new_node
|
node1__
       \
       node2
*/
static struct finsh_node* make_sys_node(uint8_t type, struct finsh_node* node1, struct finsh_node* node2)
{
	struct finsh_node* node;

	node = finsh_node_allocate(type);

	if((node1 != NULL) && (node != NULL)) {
		finsh_node_child(node) = node1;
		finsh_node_sibling(node1) = node2;
	} else finsh_error_set(FINSH_ERROR_NULL_NODE);

	return node;
}

/*
start -> statement_expr | decl_variable
*/
void finsh_parser_run(struct finsh_parser* self, const uint8_t* string)
{
	enum finsh_token_type token;
	struct finsh_node* node;

	node = NULL;

	/* init parser */
	self->parser_string = (uint8_t*)string;

	/* init token */
	finsh_token_init(&(self->token), self->parser_string);

	/* get next token */
	next_token(token, &(self->token));

	while(token != finsh_token_type_eof && token != finsh_token_type_bad) {
		switch(token) {
			case finsh_token_type_identifier:
				/* process expr_statement */
				finsh_token_replay(&(self->token));

				if(self->root != NULL) {
					finsh_node_sibling(node) = proc_expr_statement(self);

					if(finsh_node_sibling(node) != NULL)
						node = finsh_node_sibling(node);
				} else {
					node = proc_expr_statement(self);
					self->root = node;
				}

				break;

			default:
				if(is_base_type(token) || token == finsh_token_type_unsigned) {
					/* variable decl */
					finsh_token_replay(&(self->token));

					if(self->root != NULL) {
						finsh_node_sibling(node) = proc_variable_decl(self);

						if(finsh_node_sibling(node) != NULL)
							node = finsh_node_sibling(node);
					} else {
						node = proc_variable_decl(self);
						self->root = node;
					}
				} else {
					/* process expr_statement */
					finsh_token_replay(&(self->token));

					if(self->root != NULL) {
						finsh_node_sibling(node) = proc_expr_statement(self);

						if(finsh_node_sibling(node) != NULL)
							node = finsh_node_sibling(node);
						else next_token(token, &(self->token));
					} else {
						node = proc_expr_statement(self);
						self->root = node;
					}
				}

				break;
		}

		/* no root found, break out */
		if(self->root == NULL) break;

		/* get next token */
		next_token(token, &(self->token));
	}
}

int finsh_parser_init(struct finsh_parser* self)
{
	memset(self, 0, sizeof(struct finsh_parser));

	return 0;
}
